package config

import (
	"go.uber.org/zap/zapcore"
	"time"
)

type Zap struct {
	Level         string `mapstructure:"Level" yaml:"Level"`                 // 日志级别（debug/info/warn/error/dpanic/panic/fatal） 示例: "info"（只记录info及以上级别）
	Format        string `mapstructure:"Format" yaml:"Format"`               // 日志格式（console/json） console：易读的文本格式（开发环境推荐） json：结构化JSON格式（生产环境推荐）
	Directory     string `mapstructure:"Directory" yaml:"Directory"`         // 日志文件存储目录 示例: "./logs"（相对路径）或 "/var/log/myapp"（绝对路径）
	Prefix        string `mapstructure:"Prefix" yaml:"Prefix"`               // 日志文件名前缀 示例: "app" → 生成 app-2023-08-01.log
	EncodeLevel   string `mapstructure:"EncodeLevel" yaml:"EncodeLevel"`     // 日志级别编码格式（lowercase/uppercase/color） lowercase：小写（"info"） uppercase：大写（"INFO"） color：带颜色（仅console格式有效）
	StacktraceKey string `mapstructure:"StacktraceKey" yaml:"StacktraceKey"` // 堆栈跟踪的字段名（空字符串表示禁用堆栈跟踪） 示例: "stacktrace"（发生错误时记录调用堆栈）
	ShowLine      bool   `mapstructure:"ShowLine" yaml:"ShowLine"`           // 是否显示调用位置（文件和行号） true：显示（如 "main.go:42"）
	LogInConsole  bool   `mapstructure:"LogInConsole" yaml:"LogInConsole"`   // 是否同时在控制台输出日志 true：控制台和文件同时输出
	SplitType     string `mapstructure:"SplitType" yaml:"SplitType"`         // 日志分割方式（size/daily） size：按文件大小分割 daily：按天分割
	MaxSize       int    `mapstructure:"MaxSize" yaml:"MaxSize"`             // 单个日志文件最大大小（MB，仅SplitType=size时生效） 示例: 100（表示100MB）
	MaxBackups    int    `mapstructure:"MaxBackups" yaml:"MaxBackups"`       // 保留的旧日志文件最大数量 示例: 7（保留最近7天的日志）
	MaxAge        int    `mapstructure:"MaxAge" yaml:"MaxAge"`               // 旧日志文件保留天数（仅SplitType=daily时生效）示例: 30（日志保留30天）
	Compress      bool   `mapstructure:"Compress" yaml:"Compress"`           // 是否压缩旧日志文件（gzip格式） true：启用压缩（生成 .gz 文件）
}

// Levels 根据字符串转化为 zapcore.Levels
func (c *Zap) Levels() []zapcore.Level {
	levels := make([]zapcore.Level, 0, 7)
	level, err := zapcore.ParseLevel(c.Level)
	if err != nil {
		level = zapcore.DebugLevel
	}
	for ; level <= zapcore.FatalLevel; level++ {
		levels = append(levels, level)
	}
	return levels
}

func (c *Zap) Encoder() zapcore.Encoder {
	config := zapcore.EncoderConfig{
		TimeKey:       "time",
		NameKey:       "name",
		LevelKey:      "level",
		CallerKey:     "caller",
		MessageKey:    "message",
		StacktraceKey: c.StacktraceKey,
		LineEnding:    zapcore.DefaultLineEnding,
		EncodeTime: func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {
			encoder.AppendString(c.Prefix + t.Format("2006-01-02 15:04:05.000"))
		},
		EncodeLevel: c.LevelEncoder(),
		EncodeCaller: func(c zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
			enc.AppendString("|" + c.TrimmedPath())
		},
		EncodeDuration: zapcore.SecondsDurationEncoder,
	}
	if c.Format == "json" {
		return zapcore.NewJSONEncoder(config)
	}
	return zapcore.NewConsoleEncoder(config)

}

// LevelEncoder 根据 EncodeLevel 返回 zapcore.LevelEncoder
// Author [SliverHorn](https://github.com/SliverHorn)
func (c *Zap) LevelEncoder() zapcore.LevelEncoder {
	switch {
	case c.EncodeLevel == "LowercaseLevelEncoder": // 小写编码器(默认)
		return zapcore.LowercaseLevelEncoder
	case c.EncodeLevel == "LowercaseColorLevelEncoder": // 小写编码器带颜色
		return zapcore.LowercaseColorLevelEncoder
	case c.EncodeLevel == "CapitalLevelEncoder": // 大写编码器
		return zapcore.CapitalLevelEncoder
	case c.EncodeLevel == "CapitalColorLevelEncoder": // 大写编码器带颜色
		return zapcore.CapitalColorLevelEncoder
	default:
		return zapcore.LowercaseLevelEncoder
	}
}
